// 基于 SnowLang Project (https://gitee.com/jcnc-org/snow) 的衍生作品
// 原始版权归属: Copyright © 2025 Ke Xu (Luke)
// 本实现版权归属: Copyright © 2025 Sany
// 遵循 Apache License 2.0 授权
package module

import (
	"errors"
	"fmt"

	"gitee.com/xntk2381/cc/vm/utils"
)

type LocalVariableStore struct {
	localVariables []interface{}
	vmMode         VMMode
}

/* ---------- construction ---------- */

func NewLocalVariableStore(vmMode VMMode) *LocalVariableStore {
	store := &LocalVariableStore{
		localVariables: make([]interface{}, 0),
		vmMode:         vmMode,
	}
	store.handleMode()
	return store
}

func NewLocalVariableStoreWithCapacity(vmMode VMMode, initialCapacity int) *LocalVariableStore {
	store := &LocalVariableStore{
		localVariables: make([]interface{}, 0, initialCapacity),
		vmMode:         vmMode,
	}
	store.handleMode()
	return store
}

/* ---------- public API ---------- */

/** Sets the value at {@code index}, expanding the list if necessary. */
func (s *LocalVariableStore) SetVariable(index int, value interface{}) {
	s.ensureCapacity(index + 1)
	s.localVariables[index] = value
}

/* ------------------------------------------------------------
 * 兼容早期实现：VM 指令译码器可直接调用 store / load
 * 而无需关心内部命名差异。
 * ------------------------------------------------------------ */
func (s *LocalVariableStore) Store(index int, value interface{}) {
	s.SetVariable(index, value)
}

func (s *LocalVariableStore) Load(index int) (interface{}, error) {
	return s.GetVariable(index)
}

/** Returns the value at {@code index}. */
func (s *LocalVariableStore) GetVariable(index int) (interface{}, error) {
	if index < 0 {
		return nil, errors.New(fmt.Sprintf("Negative LV index: %d", index))
	}
	s.ensureCapacity(index + 1)
	return s.localVariables[index], nil
}

/** Exposes the backing list (read-only preferred). */
func (s *LocalVariableStore) GetLocalVariables() []interface{} {
	return s.localVariables
}

/** Prints every slot to the logger. */

func (s *LocalVariableStore) PrintLv() {
	if len(s.localVariables) == 0 {
		utils.LogInfo("Local variable table is empty", "")
		return
	}
	utils.LogInfo("\n### VM Local Variable Table:", "")
	for i, val := range s.localVariables {
		utils.LogInfo("", fmt.Sprintf("%d: %v", i, val))
	}
}

/** Clears all variables (used when a stack frame is popped). */
func (s *LocalVariableStore) ClearVariables() {
	s.localVariables = make([]interface{}, 0)
}

/**
 * Compacts the table by <b>removing trailing {@code null} slots</b>.
 * <p>Call this once after program termination (e.g. in
 * {@code VirtualMachineEngine.execute()} before printing) to get
 * cleaner debug output without affecting execution-time indices.</p>
 */
func (s *LocalVariableStore) Compact() {
	i := len(s.localVariables) - 1
	for i >= 0 && s.localVariables[i] == nil {
		s.localVariables = s.localVariables[:i]
		i--
	}
}

/* ---------- internal helpers ---------- */

/** Ensures backing list can hold {@code minCapacity} slots. */
func (s *LocalVariableStore) ensureCapacity(minCapacity int) {
	for len(s.localVariables) < minCapacity {
		s.localVariables = append(s.localVariables, nil)
	}
}

type LocalVariableDisplayer interface {
	Display(store *LocalVariableStore, title string)
}

var displayer LocalVariableDisplayer

func RegDisplayer(d LocalVariableDisplayer) {
	displayer = d
}

/** Mode-specific UI hook (unchanged). */
func (s *LocalVariableStore) handleMode() {
	if s.vmMode == DEBUG {
		// 注意：这里需要避免直接导入gui包导致的循环依赖
		// 可以通过接口或依赖注入的方式解决
		displayer.Display(s, "Local Variable Table")
	}
}
